package com.color.admin.system.servie.impl;

import com.color.admin.common.core.constant.Constant;
import com.color.admin.common.core.exception.BaseException;
import com.color.admin.common.core.page.PageRequest;
import com.color.admin.common.core.page.PageResponse;
import com.color.admin.common.core.utils.tools.QueryHelp;
import com.color.admin.common.core.utils.web.StringUtils;
import com.color.admin.system.entity.SysDept;
import com.color.admin.system.entity.query.DeptQueryCriteria;
import com.color.admin.system.entity.vo.dept.DeptTreeVo;
import com.color.admin.system.entity.vo.dept.DeptVo;
import com.color.admin.system.repository.DeptRepository;
import com.color.admin.system.servie.DeptService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HaiQiu
 * @date 2021/12/23
 */
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptRepository deptRepository;

    @Autowired
    private static final String TOP_PARENT_ID = "0";

    @Override
    public void save(SysDept sysDept) {
        sysDept.setParentId(StringUtils.isBlank(sysDept.getParentId()) ? TOP_PARENT_ID : sysDept.getParentId());
        sysDept.setCreateTime(new Date());
        sysDept.setUpdateTime(new Date());
        SysDept dept = deptRepository.save(sysDept);
        if (ObjectUtils.isEmpty(dept)) {
            throw new BaseException(Constant.INSERT_FAIL);
        }
    }


    @Override
    public SysDept saveRes(SysDept sysDept) {
        sysDept.setParentId(StringUtils.isBlank(sysDept.getParentId()) ? TOP_PARENT_ID : sysDept.getParentId());
        sysDept.setCreateTime(new Date());
        sysDept.setUpdateTime(new Date());
        SysDept dept = deptRepository.save(sysDept);
        if (ObjectUtils.isEmpty(dept)) {
            throw new BaseException(Constant.INSERT_FAIL);
        }
        return sysDept;
    }

    @Override
    public void update(SysDept sysDept) {
        SysDept dept = get(sysDept.getId());
        dept.setDeptName(sysDept.getDeptName());
        dept.setActive(sysDept.getActive());
        dept.setIcon(sysDept.getIcon());
        dept.setDescription(sysDept.getDescription());
        dept.setSort(sysDept.getSort());
        dept.setParentId(StringUtils.isBlank(sysDept.getParentId()) ? dept.getParentId() : sysDept.getParentId());
        sysDept.setUpdateTime(new Date());
        SysDept save = deptRepository.save(dept);
        if (ObjectUtils.isEmpty(save)){
            throw new BaseException(Constant.UPDATE_FAIL);
        }
    }


    @Override
    public SysDept updateRes(SysDept sysDept) {
        SysDept dept = get(sysDept.getId());
        dept.setDeptName(sysDept.getDeptName());
        dept.setActive(sysDept.getActive());
        dept.setIcon(sysDept.getIcon());
        dept.setDescription(sysDept.getDescription());
        dept.setSort(sysDept.getSort());
        dept.setParentId(StringUtils.isBlank(sysDept.getParentId()) ? dept.getParentId() : sysDept.getParentId());
        sysDept.setUpdateTime(new Date());
        SysDept save = deptRepository.save(dept);
        if (ObjectUtils.isEmpty(save)){
            throw new BaseException(Constant.UPDATE_FAIL);
        }
        return save;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Set<String> deptIds) {
        if (CollectionUtils.isEmpty(deptIds)) {
            throw new BaseException(Constant.ID_EXITS);
        }
        //查询是否包含子集
        List<SysDept> depts = deptRepository.findAllByParentIdIn(deptIds);
        if (!CollectionUtils.isEmpty(depts)) {
            List<String> list = depts.stream().map(SysDept::getDeptName).collect(Collectors.toList());
            throw new BaseException(String.format("删除项包含子集部门%s，请先删除子部门", list));
        }
        //删除与用户绑定
        deptRepository.deleteUsersByDeptIds(deptIds);
        if (deptRepository.deleteAllByIdIn(deptIds) == 0) {
            throw new BaseException(Constant.DELETE_FAIL);
        }
    }

    @Override
    public SysDept get(String deptId) {
        SysDept sysDept = deptRepository.findById(deptId).orElseGet(SysDept::new);
        return sysDept;
    }

    @Override
    public PageResponse<DeptVo> list(PageRequest<DeptQueryCriteria> request) {
        DeptQueryCriteria criteria = request.getParams();
        //排序
        Sort.Order order = Sort.Order.by("sort");
        if (!StringUtils.isBlank(request.getOrder()) && !StringUtils.isBlank(request.getProp())){
            if (request.getOrder().equals(Constant.DESC)){
                order = Sort.Order.desc(request.getProp());
            }else {
                order = Sort.Order.asc(request.getProp());
            }
        }
        //分页
        Pageable page = org.springframework.data.domain.PageRequest.of(request.getNum(),
                request.getPageSize(), Sort.by(order));
        //查询
        Page<SysDept> depts = deptRepository.findAll((root, query, criteriaBuilder) ->
                QueryHelp.getPredicate(root,criteria,criteriaBuilder), page);
        //实体转换
        Page<DeptVo> deptVos = depts.map(sysDept -> {
            DeptVo vo = new DeptVo();
            BeanUtils.copyProperties(sysDept, vo);
            return vo;
        });

        PageResponse<DeptVo> response = new PageResponse<>();
        response.setPageSize(request.getPageSize());
        response.setTotalElements(deptVos.getTotalElements());
        response.setPageIndex(request.getPageIndex());
        response.setData(deptVos.getContent());
        return response;
    }


    @Override
    public List<SysDept> deptAll() {
        return deptRepository.findAll();
    }

    @Override
    public List<DeptTreeVo> tree() {
        List<SysDept> depts = deptRepository.findAll(Sort.by("sort"));
        if (CollectionUtils.isEmpty(depts)) {
            return null;
        }
        //转换实体
        List<DeptTreeVo> vos = turn(depts);
        //循环递归
        List<DeptTreeVo> deptTreeVoList = recursion(vos);
        return deptTreeVoList;
    }

    @Override
    public List<SysDept> findAllByPid(String pid) {
        List<SysDept> sysDepts = deptAll();
        if (!CollectionUtils.isEmpty(sysDepts)) {
            return getDeptParentAndChildrens(sysDepts, pid);
        }
        return null;
    }

    /**
     * 查询子集和本身
     *
     * @param sysDepts 全部数据
     * @param pid      父级Id
     * @return 子集和本身
     */
    private List<SysDept> getDeptParentAndChildrens(List<SysDept> sysDepts, String pid) {
        List<SysDept> depts = new ArrayList<>();
        sysDepts.forEach(sysDept -> {
            if (sysDept.getParentId().equals(pid)) {
                depts.addAll(getDeptParentAndChildrens(sysDepts, sysDept.getId()));
            } else if (sysDept.getId().equals(pid)) {
                depts.add(sysDept);
            }
        });
        return depts;
    }

    /**
     * 递归开始循环
     *
     * @param vos 全部数据
     * @return 树形结构数据
     */
    protected List<DeptTreeVo> recursion(List<DeptTreeVo> vos) {
        String pid = "0";
        List<DeptTreeVo> deptTreeVoList = new ArrayList<>();
        vos.forEach(vo -> {
            if (pid.equals(vo.getParentId())) {
                deptTreeVoList.add(setChildData(vo, vos));
            }
        });
        return deptTreeVoList;
    }


    /**
     * 递归寻找子集
     *
     * @param vo  父级
     * @param vos 所有数据
     * @return 递归子集
     */
    protected DeptTreeVo setChildData(DeptTreeVo vo, List<DeptTreeVo> vos) {
        vos.forEach(child -> {
            if (child.getParentId().equals(vo.getId())) {
                vo.getChildren().add(setChildData(child, vos));
            }
        });
        return vo;
    }

    /**
     * 实体方法数据转换
     *
     * @param sysDepts 部门数据
     * @return 转换数据
     */
    protected List<DeptTreeVo> turn(List<SysDept> sysDepts) {
        List<DeptTreeVo> vos = sysDepts.stream().map(new Function<SysDept, DeptTreeVo>() {
            @Override
            public DeptTreeVo apply(SysDept sysDept) {
                DeptTreeVo deptTreeVo = new DeptTreeVo();
                deptTreeVo.setId(sysDept.getId());
                deptTreeVo.setDeptName(sysDept.getDeptName());
                deptTreeVo.setParentId(sysDept.getParentId());
                return deptTreeVo;
            }
        }).collect(Collectors.toList());
        return vos;
    }
}
